package com.lock.immersive.utils;

import org.springframework.util.StringUtils;

import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

public class CalendarUtil {
//  SimpleDateFormat是线程不安全的，多线程并发容易出问题，所以转为ThreadLocal变量，详情可见main方法最下面的【模拟多线程并发测试】
//	public static SimpleDateFormat longestFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
//	public static SimpleDateFormat monthFormatter = new SimpleDateFormat("yyyy-MM");
//	public static SimpleDateFormat dayFormatter = new SimpleDateFormat("yyyy-MM-dd");
//	public static SimpleDateFormat hourFormatter = new SimpleDateFormat("yyyy-MM-dd HH:00:00");
//	public static SimpleDateFormat longFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 
	private static final ThreadLocal<SimpleDateFormat> longestFormatter = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS"));
	private static final ThreadLocal<SimpleDateFormat> longFormatter = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
	private static final ThreadLocal<SimpleDateFormat> monthFormatter = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM"));
	private static final ThreadLocal<SimpleDateFormat> dayFormatter = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
	private static final ThreadLocal<SimpleDateFormat> hourFormatter = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:00:00"));
 
	private static SimpleDateFormat getLongestFormatter() {
		return longestFormatter.get();
	}
 
	private static SimpleDateFormat getLongFormatter() {
		return longFormatter.get();
	}
 
	private static SimpleDateFormat getMonthFormatter() {
		return monthFormatter.get();
	}
 
	private static SimpleDateFormat getDayFormatter() {
		return dayFormatter.get();
	}
 
	private static SimpleDateFormat getHourFormatter() {
		return hourFormatter.get();
	}
 
	//获取指定日期对应的年份
	public static int getYear(Date date) {
		if ( date != null ) {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(date);
			return calendar.get(Calendar.YEAR);
		}
		return -1;
	}
 
	//获取指定日期对应的月份
	public static int getMonth(Date date) {
		if ( date != null ) {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(date);
			return calendar.get(Calendar.MONTH) + 1;
		}
		return -1;
	}
 
	//获取指定日期对应的是当月的第几天
	public static int getDayOfMonth(Date date) {
		if ( date != null ) {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(date);
			return calendar.get(Calendar.DAY_OF_MONTH);
		}
		return -1;
	}
 
	//获取指定日期对应的是今年的第几周
	public static int getWeekOfYear(Date date) {
		if ( date != null ) {
			Calendar calendar = Calendar.getInstance();
			calendar.setFirstDayOfWeek(Calendar.MONDAY);
			calendar.setTime(date);
			return calendar.get(Calendar.WEEK_OF_YEAR);
		}
		return -1;
	}
 
	//获取指定日期对应的星期几
	public static int getDayOfWeek(Date date) {
		if ( date != null ) {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(date);
			if ( calendar.get(Calendar.DAY_OF_WEEK) == 1 ) {
				return 7;
			}
			return calendar.get(Calendar.DAY_OF_WEEK) - 1;
		}
		return -1;
	}
 
	//获取指定月份的最后一天
	public static int getLastDayOfMonth(String dateString) {
		if ( !StringUtils.isEmpty(dateString) && dateString.contains("-") ) {
			Calendar calendar = Calendar.getInstance();
			int year = Integer.valueOf(dateString.split("-")[0]);
			int month = 0;
			if ( !StringUtils.isEmpty(dateString.split("-")[1]) ) {
				month = Integer.valueOf(dateString.split("-")[1]);
			}
			// 设置年份
			calendar.set(Calendar.YEAR, year);
			calendar.set(Calendar.MONTH, month - 1);
			calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
			return calendar.get(Calendar.DAY_OF_MONTH);
		}
		return -1;
	}
 
	//获取指定日期对应的时
	public static int getHour(Date date) {
		if ( date != null ) {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(date);
			return calendar.get(Calendar.HOUR_OF_DAY);
		}
		return -1;
	}
 
	//获取指定日期对应的分
	public static int getMinute(Date date) {
		if ( date != null ) {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(date);
			return calendar.get(Calendar.MINUTE);
		}
		return -1;
	}
 
	//获取指定日期对应的秒
	public static int getSecond(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		return calendar.get(Calendar.SECOND);
	}
 
	//获取指定日期对应的是第几季度
	public static int getSeason(Date date) {
		if ( date != null ) {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(date);
			int month = calendar.get(Calendar.MONTH) + 1;
			if ( month >= 1 && month <= 3 ) {
				return 1;
			} else if ( month >= 4 && month <= 6 ) {
				return 2;
			} else if ( month >= 7 && month <= 9 ) {
				return 3;
			} else if ( month >= 10 && month <= 12 ) {
				return 4;
			} else {
				return 0;
			}
		}
		return -1;
	}
 
	//获取指定日期时间的昨天的对应日期时间
	public static Date getYesterdayOfDate(Date date) {
		if ( date != null ) {
			Calendar calendar = Calendar.getInstance();
			calendar.set(getYear(date), getMonth(date) - 1, getDayOfMonth(date));
			calendar.add(Calendar.DATE, -1);//-1.昨天时间 0.当前时间 1.明天时间 *以此类推
			return calendar.getTime();
		}
		return null;
	}
 
	//获取指定日期时间的小时(date类型)
	public static Date getHourOfDate(Date date) {
		if ( date != null ) {
			if ( getHourFormatter().format(date).matches("^[0-9]*$") ) {
				return getHourFormatter().parse(getHourFormatter().format(date), new ParsePosition(0));
			}
		}
		return null;
	}
 
	//获取指定日期时间的上一个小时的时间(date类型)
	public static Date getLastHourOfDate(Date date) {
		if ( date != null ) {
			String dateString = getHourFormatter().format(date);
			Integer hour = Integer.valueOf(dateString.substring(11, 13));
			if ( hour == 0 ) {
				Date yesterday = getYesterdayOfDate(date);
				System.out.println("yesterday:" + yesterday);
				String dayString = toDateString(getHourOfDate(yesterday));
				System.out.println("dayString:" + dayString);
				dateString = new StringBuilder(dayString).replace(11, 13, "23").toString();
			} else {
				dateString = new StringBuilder(dateString).replace(11, 13, String.valueOf(hour - 1)).toString();
			}
			return getHourFormatter().parse(dateString, new ParsePosition(0));
		}
		return null;
	}
 
	//字符串转为date类型并精确到时
	public static Date toHourOfDate(String dateString) {
		if ( !StringUtils.isEmpty(dateString) ) {
			return getHourFormatter().parse(dateString, new ParsePosition(0));
		}
		return null;
	}
 
	//字符串转为date类型并精确到天
	public static Date toDayOfDateString(String dateString) {
		if ( !StringUtils.isEmpty(dateString) ) {
			return getDayFormatter().parse(dateString, new ParsePosition(0));
		}
		return null;
	}
 
	public static String toStringOfDateString(String dateString) {
		if ( !StringUtils.isEmpty(dateString) ) {
			Date date = getDayFormatter().parse(dateString, new ParsePosition(0));
			return getDayFormatter().format(date);
		}
		return null;
	}
 
	//字符串转为date类型并精确到天
	public static Date toMonthOfDate(Date date) {
		if ( date != null ) {
			return getMonthFormatter().parse(getMonthFormatter().format(date), new ParsePosition(0));
		}
		return null;
	}
 
	//规范date类型格式精确到天
	public static String toDayStringOfDate(Date date) {
		if ( date != null ) {
			return getDayFormatter().format(date);
		}
		return null;
	}
 
	//规范date类型格式精确到天
	public static String toDayStringOfDate(long time) {
		return toDayStringOfDate(new Date(time));
	}
 
	//规范long类型毫秒值（时间戳）格式为String类型
	public static String toDateString(Long time) {
		if ( time != null ) {
			return getLongFormatter().format(new Date(time));
		}
		return null;
	}
 
	//规范long类型毫秒值（时间戳）格式为String类型
	public static Date toDate(Long time) {
		if ( time != null ) {
			return new Date(time);
		}
		return null;
	}
 
	//规范long类型毫秒值（时间戳）格式为String类型
	public static Long toMillisTime(String dateString) {
		if ( !StringUtils.isEmpty(dateString) ) {
			return getLongFormatter().parse(dateString, new ParsePosition(0)).getTime();
		}
		return null;
	}
 
	//规范long类型毫秒值（时间戳）格式为Date类型
	public static Long toMillisTime(Date date) {
		if ( date != null ) {
			return date.getTime();
		}
		return null;
	}
 
	//规范date类型格式为[长时间格式]
	public static Date toLongFormatDate(Date date) {
		if ( date != null ) {
			return getLongFormatter().parse(getLongFormatter().format(date), new ParsePosition(0));
		}
		return null;
	}
 
	//字符串转为date类型[长时间格式]
	public static Date toDate(String dateString) {
		if ( !StringUtils.isEmpty(dateString) ) {
			return getLongFormatter().parse(dateString, new ParsePosition(0));
		}
		return null;
	}
 
	//字符串转为date类型[超长时间格式]（精确到毫秒）
	public static Date toMSDate(String dateString) {
		if ( !StringUtils.isEmpty(dateString) ) {
			return getLongestFormatter().parse(dateString, new ParsePosition(0));
		}
		return null;
	}
 
	//date类型转为字符串[长时间格式]
	public static String toDateString(Date date) {
		if ( date != null ) {
			getLongFormatter().setTimeZone(TimeZone.getTimeZone("GMT+8"));
			return getLongFormatter().format(date);
		}
		return null;
	}
 
	//拼接为date类型[长时间格式]
	public static Date joinDate(Integer year, Integer month, Integer day, Date date) {
		if ( year != null && month != null && day != null && date != null ) {
			StringBuilder sb = new StringBuilder();
			sb.append(year);
			sb.append("-");
			sb.append(month);
			sb.append("-");
			sb.append(day);
			sb.append(" ");
			sb.append(getLongFormatter().format(date).split(" ")[1]);
			return getLongFormatter().parse(sb.toString(), new ParsePosition(0));
		}
		return null;
	}
 
	//计算两个日期间隔多少天
	public static int daysBetween(Date startDate, Date endDate) {
		//直接通过计算两个日期的毫秒数，他们的差除以一天的毫秒数，即可得到想要的两个日期相差的天数。
		if ( startDate != null && endDate != null ) {
			return (int)((endDate.getTime() - startDate.getTime()) / (1000 * 3600 * 24));
		}
		return -1;
	}
 
	//计算两个日期间隔多少毫秒
	public static Long msBetween(Date startDate, Date endDate) {
		//直接通过计算两个日期的毫秒数，他们的差除以一天的毫秒数，即可得到想要的两个日期相差的天数。
		if ( startDate != null && endDate != null ) {
			return endDate.getTime() - startDate.getTime();
		}
		return Long.valueOf(-1);
	}
 
	//计算两个日期间隔多少小时
	public static int hoursBetween(Date startDate, Date endDate) {
		if ( startDate != null && endDate != null ) {
			//直接通过计算两个日期的毫秒数，他们的差除以一天的毫秒数，即可得到想要的两个日期相差的天数。
			return (int)((endDate.getTime() - startDate.getTime()) / (1000 * 3600));
		}
		return -1;
	}
 
	//计算两个日期间隔多少分钟
	public static int minutesBetween(Date startDate, Date endDate) {
		//直接通过计算两个日期的毫秒数，他们的差除以一分钟的毫秒数，即可得到想要的两个日期相差的分钟数。
		if ( startDate != null && endDate != null ) {
			return (int)((endDate.getTime() - startDate.getTime()) / (1000 * 60));
		}
		return -1;
	}
 
	//计算某个日期过了指定分钟后的date时间
	public static Date minutesAfter(Date date, Double minutes) {
		if ( date != null && minutes != null && minutes >= 0.0 ) {
			Calendar cal = Calendar.getInstance();
			cal.setTime(date);
			cal.add(Calendar.MINUTE, minutes.intValue());// 24小时制
			return cal.getTime();
		}
		return null;
	}
 
	//计算某个日期过了指定分钟后的date时间
	public static Date minutesAfter(Date date, int minutes) {
		if ( date != null && minutes >= 0 ) {
			Calendar cal = Calendar.getInstance();
			cal.setTime(date);
			cal.add(Calendar.MINUTE, minutes);// 24小时制
			return cal.getTime();
		}
		return null;
	}
 
	//计算某个日期过了指定秒钟后的date时间
	public static Date secondsAfter(Date date, int seconds) {
		if ( date != null && seconds >= 0 ) {
			Calendar cal = Calendar.getInstance();
			cal.setTime(date);
			cal.add(Calendar.SECOND, seconds);// 24小时制
			return cal.getTime();
		}
		return null;
	}
 
	//计算某个日期过了指定秒钟后的date时间
	public static Date msAfter(Date date, int ms) {
		if ( date != null && ms >= 0 ) {
			Calendar cal = Calendar.getInstance();
			cal.setTime(date);
			cal.add(Calendar.MILLISECOND, ms);// 24小时制
			return cal.getTime();
		}
		return null;
	}
 
	//计算某个日期过了指定分钟后的date时间
	public static Date msAfter(Date date, Long ms) {
		if ( date != null && ms != null ) {
			Calendar cal = Calendar.getInstance();
			cal.setTime(date);
			cal.add(Calendar.MILLISECOND, ms.intValue());// 24小时制
			return cal.getTime();
		}
		return null;
	}
 
	//获取指定日期对应的月份
	public static String getLastMonthOfYear(Date date) {
		if ( date != null ) {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(date);
			int lastMonth = calendar.get(Calendar.MONTH);
			int year = calendar.get(Calendar.YEAR);
			if ( lastMonth == 0 ) {
				lastMonth = 12;
				year--;
			}
			return new StringBuilder().append(year).append("-").append(lastMonth).toString();
		}
		return null;
	}
 
	//获取几天前的时间
	public static Date getDateBeforeDays(Date d, int day) {
		Calendar now = Calendar.getInstance();
		now.setTime(d);
		now.set(Calendar.DATE, now.get(Calendar.DATE) - day);
		return now.getTime();
 
	}
 
	//获取几天后的时间
	public static Date getDateAfterDays(Date d, int day) {
		Calendar now = Calendar.getInstance();
		now.setTime(d);
		now.set(Calendar.DATE, now.get(Calendar.DATE) + day);
		return now.getTime();
	}
 
	//获取long类型时间差值转换为时分秒毫秒表达式
	public static String getMilliSecondExpression(Long secondBetween) {
		String expression = "";
		if ( secondBetween != null ) {
			Long hours = 0L;
			Long minutes = 0L;
			Long seconds = 0L;
			Long milliSeconds = 0L;
			Double floor = Math.floor(secondBetween / 3600000);
			if ( floor > 0 ) {
				hours = Math.round(floor);
				secondBetween = secondBetween - (hours * 3600000);
				expression += hours + "时 ";
			}
			floor = Math.floor(secondBetween / 60000);
			if ( floor > 0 ) {
				minutes = Math.round(floor);
				secondBetween = secondBetween - (minutes * 60000);
				expression += minutes + "分 ";
			}
			floor = Math.floor(secondBetween / 1000);
			if ( floor > 0 ) {
				seconds = Math.round(floor);
				secondBetween = secondBetween - (seconds * 1000);
				expression += seconds + "秒 ";
			}
			if ( secondBetween > 0 ) {
				milliSeconds = secondBetween;
				expression += milliSeconds + "毫秒";
			}
		}
		if ( StringUtils.isEmpty(expression) ) {
			expression = "0 毫秒";
		}
		return expression;
	}
 
}